/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.extns.bluetooth;

import java.io.DataInputStream;
import java.io.DataOutputStream;

import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;
import javax.obex.HeaderSet;
import javax.obex.Operation;
import javax.obex.ResponseCodes;
import javax.obex.ServerRequestHandler;
import javax.obex.SessionNotifier;

public final class BTServer {
	final class RequestHandler extends ServerRequestHandler {
		public void onAuthenticationFailure(byte[] userName) {
		// Send the event to the midlet
		// enqueueLibraryEvent(BTServer.this, Obex.EVENT_ON_PUT, userName);
		}

		public int onConnect(HeaderSet request, HeaderSet reply) {
			// Send the event to the midlet
			// enqueueLibraryEvent(BTServer.this, Obex.EVENT_ON_CONNECT, null);

			// Return an ok response
			return ResponseCodes.OBEX_HTTP_OK;
		}

		public int onDelete(HeaderSet request, HeaderSet reply) {
			// Send the event to the midlet
			// enqueueLibraryEvent(BTServer.this, Obex.EVENT_ON_DELETE, null);

			// Return an ok response
			return ResponseCodes.OBEX_HTTP_OK;
		}

		public void onDisconnect(HeaderSet request, HeaderSet reply) {
		// Send the event to the midlet
		// enqueueLibraryEvent(BTServer.this, Obex.EVENT_ON_DISCONNECT, null);
		}

		public int onGet(Operation op) {
			try {
				// Get the received headers
				HeaderSet headerSet = op.getReceivedHeaders();
				String name = (String) headerSet.getHeader(HeaderSet.NAME);

				// Create Object ant set output
				BTData mObexObject = new BTData(BTServer.this, name);

				// Send the event to the midlet
				// enqueueLibraryEvent(BTServer.this, Obex.EVENT_ON_GET,
				// mObexObject);

				synchronized (this) {
					wait();
				}

				// Reponse Headers
				headerSet = createHeaderSet();
				headerSet.setHeader(HeaderSet.LENGTH, new Long(mObexObject.data.length));
				op.sendHeaders(headerSet);

				// Open the outputstream
				DataOutputStream dataOutputStream = op.openDataOutputStream();
				dataOutputStream.write(mObexObject.data);
				dataOutputStream.close();

				// Close the operation
				op.close();
			} catch (Exception e) {
				// If any exception report an error
				// reportError(e);
				e.printStackTrace();
			}

			// Return an ok response
			return ResponseCodes.OBEX_HTTP_OK;
		}

		public int onPut(Operation op) {
			try {
				// Get the header set
				HeaderSet headerSet = op.getReceivedHeaders();
				String name = (String) headerSet.getHeader(HeaderSet.NAME);
				String type = (String) headerSet.getHeader(HeaderSet.TYPE);
				Long length = (Long) headerSet.getHeader(HeaderSet.LENGTH);

				// Create the data buffer
				byte[] data = new byte[(int) length.longValue()];

				// Open the inputstream and read all the data
				DataInputStream dataInputStream = op.openDataInputStream();
				dataInputStream.read(data);
				dataInputStream.close();

				// Create a response
				Object response;

				// If the request don't have name is a string or an byte array
				if (name.equals(Obex.NO_NAME)) {
					// If type is binary the response is the data
					if (type.equals(Obex.TYPE_BINARY))
						response = data;
					// The type is a string
					else
						response = new String(data);
				}
				// The reponse is a request
				else
					response = new BTData(name, type, data);

				// Close the operation
				op.close();

				// // Send the event to the midlet
				// enqueueLibraryEvent(BTServer.this, Obex.EVENT_ON_PUT,
				// response);
			} catch (Exception e) {
				// If any exception report an error
				// reportError(e);
			}

			// Return an ok response
			return ResponseCodes.OBEX_HTTP_OK;
		}

		public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
			// Send the event to the midlet
			// enqueueLibraryEvent(MObexServer.this, MObex.EVENT_ON_SET_PATH,
			// null);

			// Return an ok response
			return ResponseCodes.OBEX_HTTP_OK;
		}
	}

	/**
	 * The request handler
	 */
	protected RequestHandler requestHandler;
	private boolean running;
	/**
	 * The server UUID
	 */
	private long uuidNumber;

	/**
	 * 
	 * @param uuidNumber
	 *            server UUID
	 */
	public BTServer(long uuidNumber) {
		this.uuidNumber = uuidNumber;
		requestHandler = new RequestHandler();
	}

	/**
	 * Start the server
	 */
	public void start() {
		// If the server is already running do nothing
		if (running)
			return;

		// Create a new thread to accept clients
		new Thread() {
			public void run() {
				try {
					// Change the status of the server
					running = true;

					// Set the localdevice like discoverable
					LocalDevice localDevice = LocalDevice.getLocalDevice();
					localDevice.setDiscoverable(DiscoveryAgent.GIAC);

					// Get the UUUID
					UUID uuid = new UUID(uuidNumber);

					// Create the obex url, no authentication, no encryp, no
					// master
					String url = "btgoep://localhost:" + uuid + ";authenticate=false;master=false;encrypt=false";

					// Open the server
					SessionNotifier sessionNotifier = (SessionNotifier) Connector.open(url);

					// Accept and open the client connection
					// while the server is running
					while (running)
						sessionNotifier.acceptAndOpen(BTServer.this.requestHandler);

					// Close the server
					sessionNotifier.close();
				} catch (Exception e) {
					// If any exception, report an error
					// reportError(e);
					e.printStackTrace();
				}
			}
		}.start();
	}

	/**
	 * Stop the execution of the server
	 */
	public void stop() {
		running = false;
	}
}
